﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;

namespace MMDemo
{
 /*
  *	枚举当前可执行类型
  */
    public enum OperateTypeTree
    {
        Directory,
        Parent,
        Recessed,
    }
    class AnimationTree:InterfaceDataStructs
    {
        /// <summary>
        /// 类成员
        /// </summary>
        private Form Animation_Form = null;//演示窗体，用于构造函数的初始化
        private int Animation_width = 0;//演示窗体的宽度
        private int Animation_height = 0;//演示窗体的高度

        public Bitmap BufferBmp = null;//双缓冲画布
        private Graphics BufferGrap = null;//画笔
        private DrawHandler RefreshHandler = null;

        private char[] GenListData;
        private const int MAX_SIZE = 50; //最大数据容量
        private int GenListNum = 0;
        private int Cur_Char = -1;
        private Bitmap ImageGenList = null;
        private Bitmap ImageCurChar = null;
        private Bitmap ImagePos = null;
        private int ElementWidth = 25;
        String path = Application.StartupPath;

        private TreeNode[] ParData;
        private TreeDicData[] ParDicData;
        private int TreeDataNum = 0;

        private const int RAMY = 100;
        public AnimationTree(Form An_Form, DrawHandler refreshHandler, int An_Width, int An_Height)
        {
            this.Animation_Form = An_Form;
            this.RefreshHandler = refreshHandler;
            this.Animation_width = An_Width;
            this.Animation_height = An_Height;
            //设置画布和画笔
            BufferBmp = new Bitmap(this.Animation_width, this.Animation_height);
            BufferGrap = Graphics.FromImage(BufferBmp);
            GenListData = new char[MAX_SIZE];
            ParData = new TreeNode[20];
            ParDicData = new TreeDicData[20];

            ImageGenList = (Bitmap)Image.FromFile(path + "/image/tree_0.png");
            ImageCurChar = (Bitmap)Image.FromFile(path + "/image/tree_1.png");
            ImagePos = (Bitmap)Image.FromFile(path + "/image/tree_pos.png");
        }

        //重写初始化数据方法
        public void InitData()
        {
            ResetBuffer(Animation_width, Animation_height);
            switch (GlobalTree.operateType)
            {
                case OperateTypeTree.Directory:
                default:
                    ResetData(GlobalTree.GenList); break;
            }
            DrawGenList();
            Refresh();
        }

        /// <summary>
        /// 刷新
        /// </summary>
        /// <returns></returns>
        private bool Refresh()
        {
            try
            {
                if (Animation_Form.IsHandleCreated)
                    Animation_Form.Invoke(RefreshHandler);
            }
            catch (Exception ex)
            {
                MessageBox.Show(Animation_Form,ex.Message);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 恢复方法中调用数据初始化方法
        /// </summary>
        public void ResetData()
        {
            InitData();
        }

        /// <summary>
        /// 数据重置方法，重载
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        public void ResetData(string data)
        {
            for (int i = 0; i < data.Length;++i )
            {
                GenListData[i] = data[i];
            }
            GenListNum = data.Length;
            Cur_Char = -1;
            TreeDataNum = GlobalTree.DataNumber;

        }
        public Bitmap GetBufferBmp()
        {
            return BufferBmp;
        }
        //重新设置双缓冲画布和Graphics
        public void ResetBuffer(int Width, int Height)
        {
            this.Animation_width = Width;
            this.Animation_height = Height;
            if (null != BufferBmp)
            {
                BufferBmp.Dispose();
                BufferBmp = null;
            }
            if (null != BufferGrap)
            {
                BufferGrap.Dispose();
                BufferGrap = null;
            }

            BufferBmp = new Bitmap(this.Animation_width, this.Animation_height);
            BufferGrap = Graphics.FromImage(BufferBmp);
            DrawGenList();
            Refresh();
        }

        private bool stop_flag = false;
        public void Animation()
        {
            ElementWidth = (Animation_height - RAMY) / (TreeDataNum + 1)-10;
            switch (GlobalTree.operateType)
            {
                case OperateTypeTree.Directory:
                    stop_flag = Animation_Directory();
                    break;
                case OperateTypeTree.Recessed:
                    stop_flag = Animation_Recessed();
                    break;
                case OperateTypeTree.Parent:
                    stop_flag = Animation_Parent();
                    break;
               
            }
            if (stop_flag)
            {
                MessageBox.Show(Animation_Form, "算法演示结束!");
            }
            else
            {
                MessageBox.Show(Animation_Form, "演示动画出现异常错误!");
            }
             SysMainForm.AnimationForm.ChangeExcuteOverBtnsEnable();
        }


        private bool Animation_Recessed()
        {
            if (GenListData==null)
            {
                return false;
            }
            for (Cur_Char = 0; Cur_Char < GenListNum;++Cur_Char )
            {
                SetExcuteLine(Cur_Char * -1);
                DrawGenList();
                DrawRecessed();
                Refresh();
            }
            return true;
        }

        private bool Animation_Directory()
        {
            if (GenListData == null)
            {
                return false;
            }
            for (Cur_Char = 0; Cur_Char < GenListNum; ++Cur_Char)
            {
                SetExcuteLine(Cur_Char * -1);
                DrawGenList();
                DrawDirectory();
                Refresh();
            }
            return true;
        }

        private bool Animation_Parent()
        {
            if (GenListData == null)
            {
                return false;
            }
            for (Cur_Char = 0; Cur_Char < GenListNum; ++Cur_Char)
            {
                SetExcuteLine(Cur_Char * -1);
                DrawGenList();
                DrawParent();
                Refresh();
            }
            return true;
        }

        private void DrawRecessed()
        {
            if (GenListData == null)
            {
                return;
            }
            int x = Animation_width * 4 / 5;
            int len = Animation_width * 2 / 3;
            int y = RAMY;
            for (int i = 0; i <= Cur_Char; ++i)
            {
                if (GenListData[i]=='(')
                {
                    len -= Animation_width / 10;
                }
                else if (GenListData[i] == ')')
                {
                    len += Animation_width / 10;
                }
                else if (GenListData[i] == ',')
                {
                    
                }
                else
                {
                    y += ElementWidth + 5;
                    x = Animation_width * 4 / 5 - len;
                    BufferGrap.DrawRectangle(new Pen(Color.YellowGreen), x, y, len, ElementWidth * 2 / 3);
                    BufferGrap.DrawString(GenListData[i].ToString(), new Font("微软雅黑", 15), new SolidBrush(Color.YellowGreen), x - 30, y);
                    BufferGrap.FillRectangle(new SolidBrush(Color.Blue), x + 2, y + 2, len - 4, ElementWidth * 2 / 3 - 4);
                }
                
            }
        }


        private void DrawParent()
        {
            if (GenListData == null)
            {
                return;
            }
            int x = Animation_width / 2 - ElementWidth;
            int y = RAMY;
            int datanum = -1;
            ParData[0] = new TreeNode();
            int n = -1;
            for (int i = 0; i <= Cur_Char; ++i)
            {
                if (GenListData[i] == '(')
                {
                    ParData[datanum + 1].parent = datanum;
                }
                else if (GenListData[i] == ')')
                {
                    if (n>=0)
                    {
                        n = ParData[n].parent;
                    }                    
                    ParData[datanum + 1].parent = n;
                }
                else if (GenListData[i] == ',')
                {
                }
                else
                {
                    datanum++;
                    if (i == 0)
                    {
                        ParData[datanum].parent = -1;
                    }
                    n = ParData[datanum].parent;
                    ParData[datanum + 1] = new TreeNode(n);
                    ParData[datanum].data = GenListData[i].ToString();
                    y += (ElementWidth + 5);
                    BufferGrap.DrawString(datanum.ToString(), new Font("微软雅黑", 15), new SolidBrush(Color.Red), x - 30, y + ElementWidth / 2 - 15);
                    BufferGrap.DrawImage(ImageCurChar, x, y, ElementWidth, ElementWidth);
                    BufferGrap.DrawString(ParData[datanum].data, new Font("微软雅黑", 15), new SolidBrush(Color.Blue), x + ElementWidth / 2 - 15, y + ElementWidth / 2 - 15);
                    BufferGrap.DrawImage(ImageGenList, x + ElementWidth, y, ElementWidth, ElementWidth);
                    BufferGrap.DrawString(ParData[datanum].parent.ToString(), new Font("微软雅黑", 15), new SolidBrush(Color.Yellow), x + ElementWidth + ElementWidth / 2 - 15, y + ElementWidth / 2 - 15);
                }

            }
        }

        private void DrawDirectory()
        {
            if (GenListData == null)
            {
                return;
            }
            int x = Animation_width / 3;
            int y = RAMY;
            int datanum = -1;
            ParDicData[0] = new TreeDicData();
            int n = -1;
            for (int i = 0; i <= Cur_Char; ++i)
            {
                if (GenListData[i] == '(')
                {
                    ParDicData[datanum + 1].parent = datanum;
                    x += Animation_width / 10;
                }
                else if (GenListData[i] == ')')
                {
                    if (n >= 0)
                    {
                        n = ParDicData[n].parent;
                    }
                    ParDicData[datanum + 1].parent = n;
                    x -= Animation_width / 10;
                }
                else if (GenListData[i] == ',')
                {
                }
                else
                {
                    datanum++;
                    if (i == 0)
                    {
                        ParDicData[datanum].parent = -1;
                    }
                    n = ParDicData[datanum].parent;
                    ParDicData[datanum + 1] = new TreeDicData(n);
                    ParDicData[datanum].data = GenListData[i].ToString();
                    ParDicData[datanum].x = x;
                    y += (ElementWidth + 10);
                    ParDicData[datanum].y = y;
                    if (datanum>0)
                    {
                        DrawLinkline(ParDicData[n].x + ElementWidth / 2, ParDicData[n].y + ElementWidth, ParDicData[datanum].x, ParDicData[datanum].y + ElementWidth / 2);
                    }
                    BufferGrap.DrawImage(ImageCurChar, x, y, ElementWidth, ElementWidth);
                    BufferGrap.DrawString(ParDicData[datanum].data, new Font("微软雅黑", 15), new SolidBrush(Color.Blue), x + ElementWidth / 2 - 15, y + ElementWidth / 2 - 15);
                }

            }
        }
        /// <summary>
        /// 绘制(x1,y1)到(x2,y2)的折线
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>

        private void DrawLinkline(int x1, int y1, int x2, int y2)
        {

            Point pt1 = new Point(x1, y1);
            Point pt2 = new Point(x1, y2);
            Point pt3 = new Point(x2, y2);
            BufferGrap.DrawLine(new Pen(Color.Red,3), pt1, pt2);
            BufferGrap.DrawLine(new Pen(Color.Red,3), pt2, pt3);
            
        }
        private const int GenListWidth = 25;
        private void DrawGenList()
        {
            BufferGrap.DrawImage(PublicDataClass.DemoPicture, 0, 0, Animation_width, Animation_height);
            if (GenListData == null)
            {
                return;
            }
            int x = Animation_width / 2 - 100; ;
            int y = 60;
            BufferGrap.DrawString("广义表序列如下：", new Font("微软雅黑", 18), Brushes.Yellow, x , 20);

            for (int i = 0; i < GenListNum; ++i)
            {
                x = (Animation_width - GenListNum * GenListWidth) / 2 + i * GenListWidth;
                if (i==Cur_Char)
                {
                    BufferGrap.DrawImage(ImageCurChar, x, y, GenListWidth, 2 * GenListWidth);
                    BufferGrap.DrawString(GenListData[i].ToString(), new Font("微软雅黑", 18), Brushes.Red, x, y + 8);
                    BufferGrap.DrawImage(ImagePos, x, y + GenListWidth * 2, GenListWidth, GenListWidth);
                }
                else
                {
                    BufferGrap.DrawImage(ImageGenList, x, y, GenListWidth, 2 * GenListWidth);
                    BufferGrap.DrawString(GenListData[i].ToString(), new Font("微软雅黑", 18), Brushes.Yellow, x, y + 8);
                }
               
            }
        }


        private const int SPEED = 500;
        private int _Speed = SPEED;
        public void SetSpeed(float scale)
        {
            _Speed = (int)(SPEED * scale);
        }

        private void SetExcuteLine(int line)
        {           
            Thread.Sleep((int)(500 * PublicDataClass.scale));
            SysMainForm.AnimationForm.SetSelectLine(line);            
        }
    }

    public class TreeDicData
    {
        public string data;
        public int parent;
        public int x;
        public int y;
        public TreeDicData()
        {
            data = "";
            parent = -1;
            x = 0;
            y = 0;
        }
        public TreeDicData(int par)
        {
            data = "";
            parent = par;
            x = 0;
            y = 0;
        }
    }
}
